package com.mall.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mall.constants.OrderStatusConstant;
import com.mall.context.BaseContext;
import com.mall.domain.dto.CreateOrderDTO;
import com.mall.domain.dto.OrderPageQueryDTO;
import com.mall.domain.dto.UpdateAddressDTO;
import com.mall.domain.po.*;
import com.mall.domain.vo.OrderItemVO;
import com.mall.domain.vo.OrderDetailVO;
import com.mall.domain.vo.OrderVO;
import com.mall.exception.OrderStatusException;
import com.mall.exception.StockOutException;
import com.mall.mapper.*;
import com.mall.result.PageResult;
import com.mall.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @description: 订单服务实现
 * @author 勾新杰
 * @version 1.0
 * @date 2024/11/25 10:45
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final CartMapper cartMapper;

    private final ItemMapper itemMapper;

    private final OrderMapper orderMapper;

    private final OrderItemMapper orderItemMapper;

    private final CategoryMapper categoryMapper;

    private final UserMapper userMapper;

    /**
     * 创建订单
     *
     * @param createOrderDTO 创建订单传输对象
     */
    @Override
    @Transactional
    public void createOrder(CreateOrderDTO createOrderDTO) {
        // 1. 获取用户id
        Long userId = BaseContext.getCurrentId();
        // 2. 构建订单对象
        Order order = Order.builder()
                .userId(userId)
                .addressId(createOrderDTO.getAddressId())
                .orderNo(System.currentTimeMillis())
                .orderStatus(OrderStatusConstant.UNPAID)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        // 3. 计算订单总金额
        // 3.1. 获取购物车列表
        List<Cart> cartList = cartMapper.getByUserId(userId);
        // 3.2. 遍历购物车列表，计算总金额，并且扣减商品库存
        double totalAmount = 0;
        for (Cart cart : cartList) {
            // 3.2.1 获取商品
            Item item = itemMapper.getById(cart.getItemId());
            // 3.2.2 计算总金额
            totalAmount += cart.getQuantity() * item.getPrice();
            // 3.2.3 扣减商品库存
            if (item.getStock() < cart.getQuantity()) {
                throw new StockOutException("库存不足");
            }
            itemMapper.deductStock(cart.getItemId(), cart.getQuantity());
        }
        // 3.3. 设置订单总金额
        order.setTotalAmount(totalAmount);
        // 4. 插入订单
        orderMapper.insert(order);
        // 5. 插入订单详情
        // 5.1. 获取订单id
        Long orderId = orderMapper.getByOrderNo(order.getOrderNo()).getId();
        // 5.2. 遍历购物车列表，插入订单详情
        for (Cart cart : cartList) {
            // 5.2.1 构建订单详情
            Double price = itemMapper.getById(cart.getItemId()).getPrice();
            OrderItem orderItem = OrderItem.builder()
                    .orderId(orderId)
                    .itemId(cart.getItemId())
                    .quantity(cart.getQuantity())
                    .price(price)
                    .subtotal(cart.getQuantity() * price)
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
            // 5.2.2 插入订单详情
            orderItemMapper.insert(orderItem);
        }
        // 6. 清空购物车
        cartMapper.deleteByUserId(userId);
    }

    /**
     * 修改订单地址
     *
     * @param updateAddressD 修改订单地址传输对象
     */
    @Override
    public void updateAddress(UpdateAddressDTO updateAddressD) {
        // 1. 构建订单对象
        Order order = Order.builder()
                .id(updateAddressD.getOrderId())
                .addressId(updateAddressD.getAddressId())
                .updateTime(LocalDateTime.now())
                .build();
        // 2. 更新订单
        orderMapper.update(order);
    }

    /**
     * 订单详情
     *
     * @param id 订单id
     * @return 订单视图
     */
    @Override
    public OrderDetailVO orderDetail(Long id) {
        // 1. 获取订单
        Order order = orderMapper.getById(id);
        // 2. 获取订单详情
        List<OrderItem> orderItemList = orderItemMapper.getByOrderId(order.getId());
        // 3. 构建订单视图
        // 3.1 拷贝订单对象
        OrderDetailVO orderVO = BeanUtil.copyProperties(order, OrderDetailVO.class);
        // 3.2 构建订单详情视图
        List<OrderItemVO> orderItemVOList = new ArrayList<>();
        for (OrderItem orderItem : orderItemList) {
            // 3.2.1 获取商品和分类
            Item item = itemMapper.getById(orderItem.getItemId());
            Category category = categoryMapper.getById(item.getCategoryId());
            // 3.2.2 构建订单详情视图
            OrderItemVO orderItemVO = OrderItemVO.builder()
                    .id(orderItem.getId())
                    .itemId(orderItem.getItemId())
                    .quantity(orderItem.getQuantity())
                    .subtotal(orderItem.getSubtotal())
                    .categoryId(item.getCategoryId())
                    .categoryName(category.getName())
                    .build();
            // 3.2.3 拷贝商品对象并赋值
            BeanUtil.copyProperties(item, orderItemVO);
            orderItemVOList.add(orderItemVO);
        }
        // 3.3 设置订单详情
        orderVO.setOrderItemList(orderItemVOList);
        // 4. 返回订单视图
        return orderVO;
    }

    /**
     * 分页查询订单
     * @param orderPageQueryDTO 分页查询传输对象
     * @return 订单视图
     */
    @Override
    public PageResult<OrderVO> page(OrderPageQueryDTO orderPageQueryDTO) {
        PageHelper.startPage(orderPageQueryDTO.getPageNo(), orderPageQueryDTO.getPageSize());
        Page<OrderVO> page = orderMapper.page(orderPageQueryDTO);
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    /**
     * 发货
     *
     * @param id 订单id
     */
    @Override
    public void deliver(Long id) {
        // 1. 校验订单状态
        if (!Objects.equals(orderMapper.getById(id).getOrderStatus(), OrderStatusConstant.UNSHIPPED)){
            throw new OrderStatusException("订单状态异常");
        }
        // 2. 构建订单对象
        Order order = Order.builder()
                .id(id)
                .orderStatus(OrderStatusConstant.SHIPPED)
                .deliveryTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        // 3. 更新订单
        orderMapper.update(order);
    }

    /**
     * 批量发货
     *
     * @param ids 订单id集合
     */
    @Override
    public void deliverBatch(List<Long> ids) {
        orderMapper.deliverBatch(ids, OrderStatusConstant.SHIPPED);
    }

    /**
     * 取消订单
     *
     * @param id 订单id
     */
    @Override
    @Transactional
    public void cancelOrder(Long id) {
        // 1. 获取订单
        Order order = orderMapper.getById(id);
        // 2. 校验订单状态
        if (!Objects.equals(order.getOrderStatus(), OrderStatusConstant.UNPAID)
                && !Objects.equals(order.getOrderStatus(), OrderStatusConstant.UNSHIPPED)){
            throw new OrderStatusException("您的订单已发货，无法取消的订单");
        }
        // 3. 恢复库存
        List<OrderItem> orderItemList = orderItemMapper.getByOrderId(id);
        for (OrderItem orderItem : orderItemList) {
            itemMapper.inductStock(orderItem.getItemId(), orderItem.getQuantity());
        }
        // 4. 如果状态是未支付，则删除订单
        if (Objects.equals(order.getOrderStatus(), OrderStatusConstant.UNPAID)){
            orderMapper.deleteById(id);
        }
        // 5. 如果状态是已发货，则退款和设置订单状态为已退货，不要删除订单
        else {
            // 5.1 退款
            userMapper.inductBalance(order.getTotalAmount(), order.getUserId());
            // 5.2 更新订单状态
            Order update = Order.builder()
                    .id(id)
                    .orderStatus(OrderStatusConstant.RETURNED)
                    .updateTime(LocalDateTime.now())
                    .build();
            orderMapper.update(update);
        }
    }

    /**
     * 确认收货
     *
     * @param id 订单id
     */
    @Override
    public void confirmReceipt(Long id) {
        // 1. 校验订单状态
        Order order = orderMapper.getById(id);
        if (!Objects.equals(order.getOrderStatus(), OrderStatusConstant.SHIPPED)){
            throw new OrderStatusException("订单状态异常");
        }
        // 2. 更新订单
        Order update = Order.builder()
                .id(id)
                .orderStatus(OrderStatusConstant.RECEIVED)
                .updateTime(LocalDateTime.now())
                .build();
        orderMapper.update(update);
    }
}
